package sdu.ltp.resolve;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;

import org.apache.log4j.Logger;

import sdu.ltp.entity.BaseRel;

public abstract class AbstractTreeResolver extends AbstractResolver {

    private final Logger logger = Logger.getLogger(AbstractTreeResolver.class);
    private Map<String,Integer> datas = new HashMap<>();

    /**
     * 树形数据节点结构
     * @author ljh_2015
     *
     */
    class TreeNode {

	/**
	 * 坐标
	 */
	int x,y,z;

	Node data;

	TreeNode coo = null;

	TreeNode leftNode = null;

	TreeNode rightNode = null;

	double weight;

	public TreeNode(Node node) {
	    this.data = node;
	}

    }


    /* (non-Javadoc)
     * @see sdu.ltp.resolve.AbstractResolver#resolve(sdu.ltp.resolve.BaseData)
     * 解析玩数据再加初始化封装
     */
    @Override
    public Map<String,List<Node>> resolveData(BaseData base) {
	//第一步：解析数据
	super.resolve(base);
	//logger.info("\n"+base.getText());
	//第二步：将数据包装成“降幂树”,降幂树是指根据树的层次降低树的指数级，从而减弱深层元素对主干元素的影响
	TreeNode node = packageIn();
	//第三步：根据系数赋权重值
	weight(node,0.1,1, 0);
	//第四不：显示“降幂树”节点分析结果
	Map<String,List<Node>> results = new HashMap<>();
	viewNode(node,0,0,0,results);

	//StatisticsTemplate.sortMap(datas);
	//第五步:对结果进行统计
	//StatisticsTemplate.statistics(node);
	return results;
    }

    public void showBase() {
	StatisticsTemplate.sortMap(datas);
    }


    /**
     * 将解析的数据封装好
     */
    /**
     * 
     */
    private TreeNode packageIn() {
	//初始核心为-1
	TreeNode root = null;
	//parent队列
	Queue<Integer> parentQueue = new LinkedList<>();
	parentQueue.offer(-1);
	while(!parentQueue.isEmpty()) {
	    int headp = parentQueue.poll();
	    TreeNode lnode = null;
	    TreeNode rnode = null;
	    TreeNode coonode = null;
	    for(int i=nodes.size()-1;i>=0;i--) {
		//如果当前在寻找root节点
		if(headp==-1) {
		    if(nodes.get(i).parent == -1) {
			Node node = nodes.remove(i);
			root = new TreeNode(node);
			//将root节点的id推入parentQueue中
			parentQueue.offer(node.id);
			break;
		    } 
		} else {
		    if(nodes.get(i).parent == headp) {
			Node node = nodes.remove(i);
			TreeNode current = new TreeNode(node);
			//如果是并列关系
			if(companyRelate(node.relate)) {
			    current.coo = coonode;
			    coonode = current;
			} else {
			    current.rightNode = lnode;
			    lnode = current;
			}
			parentQueue.offer(node.id);
		    }
		}
	    }
	    if(headp!=-1) {
		TreeNode p = findTreeNode(root, headp);
		if(p==null) {
		} else {
		    addLeft(p, lnode);
		    addRight(p, rnode);
		    addCoo(p,coonode);
		}
	    }

	}
	return root;
    }


    /**
     * 判断是并列关系还是其他关系
     * @param relate
     * @return
     */
    private boolean companyRelate(String relate) {
	if("coo".equalsIgnoreCase(relate))
	    return true;
	return false;
    }

    /**
     * 寻找id = 参数parentid的点
     * @param parentid
     * @return
     */
    private TreeNode findTreeNode(TreeNode root,int parentid) {
	TreeNode temp = root;
	if(root==null) {
	    return null;
	}
	if(temp.data.id == parentid) 
	    return temp;
	TreeNode node;
	if(temp.coo!=null) {
	    node = findTreeNode(temp.coo,parentid);
	    if(node!=null) {
		return node;
	    }
	}
	if(temp.leftNode!=null) {
	    node = findTreeNode(temp.leftNode,parentid);
	    if(node!=null) {
		return node;
	    }
	} 
	return findTreeNode(temp.rightNode,parentid);
    }

    private void addLeft(TreeNode parent,TreeNode son) {
	if(son==null) 
	    return;
	if(parent.leftNode == null) {
	    parent.leftNode = son;
	}
    }

    private void addCoo(TreeNode parent,TreeNode son) {
	if(son==null) {
	    return;
	}
	if(parent.coo == null) {
	    parent.coo = son;
	}
    }

    private void addRight(TreeNode parent,TreeNode son) {
	if(son==null) {
	    return;
	}
	if(parent.rightNode == null) {
	    parent.rightNode = son;
	}
    }

    /**
     * 根据一定算法
     * 计算降幂树每个节点的权重值
     * @param root 当前节点根节点
     * @param k 计算系数
     * @param deep 计算深度
     * @param cur 当前值，累积作用
     * @return
     */
    private double weight(TreeNode root,double k,int deep,double cur) {
	double temp = cur;
	if(root.coo!=null) {
	    cur+=weight(root.coo,0.9*k,deep,temp);
	}
	if(root.leftNode!=null) {
	    cur+=weight(root.leftNode,k,deep+1,temp);
	}
	if(root.rightNode!=null) {
	    cur+=weight(root.rightNode,k,deep,temp);
	}
	cur+=childrenIndexs(root)*Math.pow(k, deep);
	//保存两位小数
	DecimalFormat df = new DecimalFormat("######0.000");
	root.weight = Double.valueOf(df.format(cur));
	return cur;
    }

    private int childrenIndexs(TreeNode node) {
	if(node==null)
	    return 0;
	return childrenIndexs(node.coo)+childrenIndexs(node.leftNode)+childrenIndexs(node.rightNode)+1;
    }

    /**
     * 节点显示,将遍历坐标赋给节点
     * @param root 当前节点
     * @param x 表示节点当前树下当前层的序列节点号
     * @param y 表示节点的层级
     * @param z 表示节点的并列深度
     */
    private void viewNode(TreeNode root,int x,int y,int z,Map<String,List<Node>> mainValue) {
	if(root==null) {

	} else {
	    root.x = x;
	    root.y = y;
	    root.z = z;
	    String key = root.data.parent+"_"+y+"_"+z;
	    List<Node> rel = mainValue.getOrDefault(key, new ArrayList<>());
	    rel.add(root.data);
	    BaseRel.putKey(root.data.relate);
	    mainValue.put(key, rel);
	    logger.info("("+x+","+y+","+z+")\t|id:"+root.data.id+"\t|pos:"+root.data.pos+"\t|parent:"+root.data.parent+"\t|relate:"+root.data.relate+"\t|weight:"+root.weight+"\t|cont:"+root.data.text);
	    //System.out.println("("+x+","+y+","+z+")\t|id:"+root.data.id+"\t|pos:"+root.data.pos+"\t|parent:"+root.data.parent+"\t|relate:"+root.data.relate+"\t|weight:"+root.weight+"\t|cont:"+root.data.text);
	    viewNode(root.rightNode,x+1,y,z,mainValue);
	    viewNode(root.leftNode,x,y+1,z,mainValue);
	    viewNode(root.coo,x,y,z+1,mainValue);
	}
    }

}
